<?php

namespace App\ApiCall\Wx\Pay;

use App\ApiCall\ApiCallBasicAbstract;
use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;


class WxPayClient extends ApiCallBasicAbstract
{
    /**
     * 微信的appId有点特殊 是一个数组
     * @param $appId
     * @param $appKey
     * @param $url
     * @return ApiCallBasicAbstract|WxPayClient|mixed|null
     */
    public static function getInstance($appId, $appKey, $url)
    {
        if(!self::$instance){
            self::$instance = new WxPayClient($appId, $appKey, $url);
        }
        return self::$instance;
    }


    /**
     * 计算签名值
     * @param $requestSign
     * @param $certKey
     * @return string
     * 使用商户私钥对待签名串进行SHA256 with RSA签名，并对签名结果进行Base64编码得到签名值
     */
    public function calculateSignatureValue($requestSign, $certKey)
    {
//        $certKey = file_get_contents($certKey);
        openssl_sign($requestSign, $raw_sign, $certKey, 'sha256WithRSAEncryption');
        $sign = base64_encode($raw_sign);
        return $sign;
    }

    /**
     * 获取token
     * @param $merchant_id
     * @param $nonce
     * @param $timestamp
     * @param $serial_no
     * @param $sign
     * @return string
     */
    public function createToken($merchant_id, $nonce, $timestamp, $serial_no, $sign)
    {
        // 默认认证类型
        $schema = 'WECHATPAY2-SHA256-RSA2048';
        $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $merchant_id, $nonce, $timestamp, $serial_no, $sign);
        return $token;
    }

    function RequestSign($method = "POST", $url = "", $request = "", $wxMerchantId, $certKey, $wxApiSerialNo)
    {
        #截取获取当前请求地址【去除域名】
        $url_parts = parse_url($url);
        $path = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        #获取当前时间戳
        $timeStamp = time();
        #生成一个随机字符串
        $nonceStr = strtoupper(md5(time()));
        #构造签名串
        $requestSign = sprintf("%s\n%s\n%s\n%s\n%s\n", $method, $path, $timeStamp, $nonceStr, $request);
        #计算计算签名值
        $sign = $this->calculateSignatureValue($requestSign, $certKey);
        #设置HTTP头获取Authorization
        $token = $this->createToken($wxMerchantId, $nonceStr, $timeStamp, $wxApiSerialNo, $sign);
        #返回
        return $token;
    }

    function execute($path, $data)
    {
        $merchantInfo = $this->appId;
        $fileUrls = $this->appKey;
        // 商户号 这里是特殊的处理
        $merchantId = $merchantInfo['merchantId'];
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = file_get_contents($fileUrls['api_client_key_url']);
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
        // 「商户API证书」的「证书序列号」
        $merchantCertificateSerial = $merchantInfo['merchantCertificateSerial'];
        // 从本地文件中加载「微信支付平台证书」(可使用证书下载工具得到），用来验证微信支付应答的签名
        $platformCertificateFilePath = file_get_contents($fileUrls['api_shop_cert_url']);
        $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
        // 从「微信支付平台证书」中获取「证书序列号」
        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);

        // 构造一个 APIv3 客户端实例
        $instance = Builder::factory([
            'mchid'      => $merchantId,
            'serial'     => $merchantCertificateSerial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs'      => [
                $platformCertificateSerial => $platformPublicKeyInstance,
            ],
        ]);

        $authorization = $this->RequestSign($this->requestType, $path, "", $merchantId, $merchantPrivateKeyFilePath, $merchantCertificateSerial);
        $this->header = [
            'Content-Type: application/json; charset=utf-8',
            'Authorization: ' . "WECHATPAY2-SHA256-RSA2048" . $authorization,
            'Accept: application/json',
            'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'
        ];
        if($this->requestType=='GET'){
            $resp = $instance
                ->chain($path)
                ->get(['json' => $data]);
        }else{
            $resp = $instance
                ->chain($path)
                ->post(['json' => $data]);
        }
        dump(1);
        return $resp->getBody();
    }
}
